package xyz.scootaloo.kami.ping

import io.vertx.core.*
import io.vertx.core.http.HttpServer
import io.vertx.core.impl.logging.LoggerFactory
import io.vertx.kotlin.core.vertxOptionsOf

/**
 * @author flutterdash@qq.com
 * @since 2022/4/4 23:46
 */
class Main(private val port: Int) : AbstractVerticle() {

    private val log by lazy { LoggerFactory.getLogger(Main::class.java) }

    override fun start(startPromise: Promise<Void>) {
        startHttpServer(startPromise).onFailure { err ->
            log.error("server start failure, cause by: ${err.message}")
            vertx.close().onSuccess {
                log.info("server exit.")
            }
        }
    }

    private fun startHttpServer(promise: Promise<Void>): Future<HttpServer> {
        val server = vertx.createHttpServer()
        server.requestHandler { req ->
            val ipAddress = req.remoteAddress()
            val uri = req.uri()
            log.info("request from $ipAddress, uri: $uri")
            req.response().end("hello $ipAddress !!")
        }
        return server.listen(port).onComplete { done ->
            if (done.succeeded()) {
                log.info("server start succeeded; listen on: $port")
                promise.complete()
            } else {
                promise.fail(done.cause())
            }
        }
    }

    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            printBanner()
            boot(getPort(args))
        }

        private fun printBanner() {
            val log = LoggerFactory.getLogger("start")
            val versionMessage = "version: v0.1"
            log.info(versionMessage)
        }

        private fun getPort(args: Array<String>): Int {
            val defPort = 80
            if (args.isEmpty())
                return defPort
            return try {
                val portStr = args[0]
                portStr.toInt()
            } catch (anyEx: Throwable) {
                defPort
            }
        }

        private fun boot(port: Int) {
            val vertx = Vertx.vertx(deployVertxOptions())
            vertx.deployVerticle(Main(port))
        }

        private fun deployVertxOptions(): VertxOptions =
            vertxOptionsOf(
                eventLoopPoolSize = 2,
                workerPoolSize = 2,
                internalBlockingPoolSize = 2
            )
    }

}